package com.aiden.app.common.base

import android.app.Activity
import android.content.Intent
import android.graphics.drawable.AnimationDrawable
import android.net.ConnectivityManager
import android.net.Network
import android.net.NetworkRequest
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.provider.Settings
import android.support.v4.app.Fragment
import android.support.v7.app.AlertDialog
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
import android.widget.TextView
import com.aiden.app.common.R
import com.aiden.app.common.extension.connectivityManager
import com.aiden.app.common.extension.onClick
import com.aiden.app.common.extension.setVisible
import com.aiden.app.common.util.NetworkUtil
import com.aiden.app.common.widget.dialog.LoadingDialog
import com.lxj.xpopup.XPopup
import com.lxj.xpopup.core.BasePopupView
import com.tbruyelle.rxpermissions2.RxPermissions
import kotlinx.android.synthetic.main.base_page_error_fragment.*
import kotlinx.android.synthetic.main.error_view.*
import kotlinx.android.synthetic.main.loading_view.*
import kotlinx.android.synthetic.main.net_error_view.*

/**
 * 懒加载fragment
 * @author yanggeng
 * @date 2018/12/12 15:52
 */
abstract class BaseFragment : Fragment() {

    protected lateinit var mInflater: LayoutInflater
    protected var mContainer: ViewGroup? = null
    protected lateinit var mActivity: Activity
    private var mIsVisibleToUser = false
    private var mIsLoadedData = false
    private var mIsViewCreated = false
    private var mIsHidden = true
    private lateinit var mPermissions: Array<String>
    private lateinit var mPermissionListener: OnRequestPermissionListener
    private var mRxPermissions: RxPermissions? = null
    private var mPermissionDialog: AlertDialog? = null
    private lateinit var multiple: FrameLayout
    protected val REQEUST_CODE_PERMISSION = 0x111
    protected var showMultipleStatusView = true
    private lateinit var loadingDialog: BasePopupView
    private lateinit var realContent: View
    protected lateinit var tvNotice: TextView
    private var animationDrawable: AnimationDrawable? = null
    private var isRequestNet = true

    abstract fun initView(): View

    abstract fun initData()

    abstract fun setListener()

    open fun loadData() {
        showLoading(true)
    }

    open fun isUseParentErrorView(): Pair<Boolean, Int?> {
        return Pair(true, null)
    }

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        mInflater = inflater
        mContainer = container
        mActivity = activity!!
        realContent = initView()
        loadingDialog = XPopup.Builder(mActivity).hasShadowBg(false).asCustom(LoadingDialog(mActivity))

        if (isUseParentErrorView().first) { // 使用了父类的 ErrorView
            if (showMultipleStatusView) {
                val content = inflater.inflate(R.layout.fragment_base, container, false)
                multiple = content.findViewById(R.id.multiple)
                multiple.addView(realContent, ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT))

                val errorView = LayoutInflater.from(mActivity).inflate(R.layout.base_page_error_fragment, null)
                multiple.addView(errorView, ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT))
                tvNotice = content.findViewById(R.id.tv_notice)
                return content
            } else {
                return realContent
            }
        } else { // 没有使用父类的 ErrorView
            val content = inflater.inflate(R.layout.fragment_base, container, false)
            multiple = content.findViewById(R.id.multiple)
            multiple.addView(realContent, ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT))
            tvNotice = multiple.findViewById(R.id.tv_notice)

            realContent = multiple.findViewById(isUseParentErrorView().second!!)
            return content
        }
    }

    /**
     * ViewPager场景下回调，在onActivityCreated回调之前执行
     */
    override fun setUserVisibleHint(isVisibleToUser: Boolean) {
        super.setUserVisibleHint(isVisibleToUser)
        this.mIsVisibleToUser = isVisibleToUser
        tryToLoad()
    }

    override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)
        this.mIsViewCreated = true
        setListener()
        tryToLoad()
    }

    /**
     * FragmentManager管理fragment场景下回调，在onActivityCreated回调后执行
     */
    override fun onHiddenChanged(hidden: Boolean) {
        super.onHiddenChanged(hidden)
        this.mIsHidden = hidden
        if (!mIsHidden) {
            tryToLoad1()
        }
    }

    override fun onResume() {
        super.onResume()
        if (!mIsLoadedData) {
            tryToLoad1()
        }
    }

    override fun onDestroyView() {
        super.onDestroyView()
        mIsLoadedData = false
    }

    fun showContent() {
        if (!showMultipleStatusView) {
            return
        }
        realContent.setVisible(true)
        error_view.setVisible(false)
        empty_view.setVisible(false)
        loading_view.setVisible(false)
        net_error_view.setVisible(false)
        dismissLoadingDialog()
        stopLoading()
    }

    fun showLoading(isUsePageLoading: Boolean = false, emptyHint: String = "暂无数据") {
        if (isUsePageLoading) {
            if (!showMultipleStatusView) {
                return
            }
            realContent.setVisible(false)
            error_view.setVisible(false)
            empty_view.setVisible(false)
            loading_view.setVisible(true)
            net_error_view.setVisible(false)
            if (animationDrawable == null) {
                iv_loading.setImageResource(R.drawable.comm_refresh)
                animationDrawable = iv_loading.drawable as AnimationDrawable
            }
            animationDrawable?.start()
        } else {
            showLoadingDialog(emptyHint)
        }
    }

    fun showError(func: () -> Unit) {
        if (!showMultipleStatusView) {
            return
        }
        if (NetworkUtil.isNetAvailable(mActivity)) {
            realContent.setVisible(false)
            error_view.setVisible(true)
            empty_view.setVisible(false)
            loading_view.setVisible(false)
            net_error_view.setVisible(false)
            stopLoading()
            dismissLoadingDialog()
            error_retry_view.onClick {
                func()
            }
        } else {
            showNoNetwork(func)
        }
    }

    fun isShowEmptyOrNot(isNotEmpty: Boolean, emptyHint: String = "暂无数据") {
        if (isNotEmpty) {
            showContent()
        } else {
            showEmpty(emptyHint)
        }
    }

    fun showNoNetwork(func: () -> Unit) {
        if (!showMultipleStatusView) {
            return
        }
        realContent.setVisible(false)
        error_view.setVisible(false)
        empty_view.setVisible(false)
        loading_view.setVisible(false)
        net_error_view.setVisible(true)
        stopLoading()
        dismissLoadingDialog()
        ll_net_error.onClick {
            func()
        }
    }

    fun showEmpty(notice: String = "暂无数据") {
        if (!showMultipleStatusView) {
            return
        }
        realContent.setVisible(false)
        error_view.setVisible(false)
        empty_view.setVisible(true)
        tvNotice.text = notice
        loading_view.setVisible(false)
        net_error_view.setVisible(false)
        stopLoading()
        dismissLoadingDialog()
    }

    open fun onNetAvailable() {
    }

    open fun onNetDisconnect() {
        showNoNetwork { loadData() }
    }

    protected fun stopLoading() {
        if (animationDrawable != null && animationDrawable?.isRunning!!) {
            animationDrawable?.stop()
        }
    }

    protected fun showLoadingDialog(title: String = "") {
        loadingDialog.show()
    }

    protected fun dismissLoadingDialog() {
        if (!loadingDialog.isDismiss) {
            loadingDialog.dismiss()
        }
    }

    /**
     * ViewPager场景下，判断父fragment是否可见
     */
    private fun isParentVisible(): Boolean {
        val fragment = parentFragment
        return fragment == null || (fragment is BaseFragment && fragment.mIsVisibleToUser)
    }

    /**
     * ViewPager场景下，若父fragment可见，则尝试让可见的子fragment加载数据
     */
    private fun dispatchParentVisibleState() {
        val fragments: List<Fragment> = fragmentManager!!.fragments
        if (fragments.isEmpty()) {
            return
        }
        for (child: Fragment in fragments) {
            if (child is BaseFragment && child.mIsVisibleToUser) {
                child.tryToLoad()
            }
        }
    }

    /**
     * ViewPager场景下加载数据
     */
    private fun tryToLoad() {
        if (mIsViewCreated && mIsVisibleToUser && isParentVisible() && !mIsLoadedData) {
            initData()
            loadData()
            mIsLoadedData = true

            dispatchParentVisibleState()
        }
    }

    /**
     * FragmentManager管理fragment情况下，判断父fragment是否隐藏
     */
    private fun isParentHidden(): Boolean {
        val fragment = parentFragment ?: return false
        if (fragment is BaseFragment && !fragment.isParentHidden()) {
            return false
        }
        return true
    }

    /**
     * FragmentManager管理Fragment情况下，当fragment显示时，对显示的子fragment尝试加载数据
     */
    private fun dispatchParentHiddenState() {
        val fragments: List<Fragment> = fragmentManager!!.fragments
        if (fragments.isEmpty()) {
            return
        }
        for (child in fragments) {
            if (child is BaseFragment && !child.mIsHidden) {
                child.tryToLoad1()
            }
        }
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        requestPermission(permissions = *mPermissions, listener = mPermissionListener)
    }

    /**
     * FragmentManager管理fragment情况下，加载数据
     */
    private fun tryToLoad1() {
        if (mIsViewCreated && !isParentHidden() && !mIsLoadedData) {
            initData()
            loadData()
            mIsLoadedData = true
            dispatchParentHiddenState()
        }
    }

    protected fun requestPermission(vararg permissions: String, listener: OnRequestPermissionListener) {
        if (mRxPermissions == null) {
            mRxPermissions = RxPermissions(this)
        }

        mPermissions = permissions as Array<String>
        val disposable = mRxPermissions!!.requestEachCombined(*permissions).subscribe { permission ->
            if (permission.granted) {
                // 获取到所有权限
                listener.onGranted()
            } else if (permission.shouldShowRequestPermissionRationale) {
                // 有至少一个权限被拒绝且没有勾选不再提示
                listener.onDenied()
            } else {
                // 有至少一个权限被拒绝且勾选不再提示
                listener.onDenied()
                showPermissionNoticeDialog()
            }
        }

    }

    /**
     * 拒绝并不再提示的权限 提示去设置页面设置
     */
    protected fun showPermissionNoticeDialog() {
        if (mPermissionDialog == null) {
            mPermissionDialog = AlertDialog.Builder(context!!)
                    .setMessage(R.string.permission_notice)
                    .setNegativeButton(R.string.cancel) { dialog, which -> }
                    .setPositiveButton(R.string.setting) { dialog, which ->
                        val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
                        val uri: Uri = Uri.fromParts("package", context?.packageName, null)
                        intent.data = uri
                        startActivityForResult(intent, REQEUST_CODE_PERMISSION)
                    }
                    .create()
        }
        mPermissionDialog!!.show()
    }

    protected fun dontListenNetWork() {
        isRequestNet = false
    }

    private fun listenNetWork() {
        if (isRequestNet && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            mActivity.connectivityManager.requestNetwork(NetworkRequest.Builder().build(), object : ConnectivityManager.NetworkCallback() {
                override fun onAvailable(network: Network?) {
                    mActivity.runOnUiThread {
                        onNetAvailable()
                    }
                }

                override fun onLost(network: Network?) {
                    mActivity.runOnUiThread {
                        onNetDisconnect()
                    }
                }
            })
        }
    }
}